package com.mes.schedule.manager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mes.common.exception.bo.BaseBusinessException;
import com.mes.schedule.dao.ScheduleOverTimeDao;
import com.mes.schedule.domain.DeviceStatistics;
import com.mes.schedule.domain.Resource;
import com.mes.schedule.domain.Resource.SegementUse;
import com.mes.schedule.domain.SCalendar;
import com.mes.schedule.domain.SDevice;
import com.mes.schedule.domain.SOperationTask;
import com.mes.schedule.domain.SPartTask;
import com.mes.schedule.domain.ScheduleOverTime;
import com.mes.schedule.domain.ScheduleScheme;
import com.mes.schedule.domain.UcDevice;
import com.mes.schedule.mm.DBHandler;
import com.mes.schedule.util.ScheduleUtils;

@Component("scheduleAnalysis")
public class ScheduleAnalysis {
	private final static Log log = LogFactory.getLog(ScheduleAnalysis.class);
	@javax.annotation.Resource
	private ScheduleDeviceManager scheduledeviceManager;
	@javax.annotation.Resource
	public ScheduleOverTimeDao scheduleOverTimeDao;
	@javax.annotation.Resource
	private ScheduleOperationTaskManager scheduleOperationTaskManager;

	public void calDeviceStatistics(ScheduleScheme scheme) {
		for (SDevice device : scheme.getDeviceMap().values()) {
			if (!device.getVirtual())
				this.scheduledeviceManager.calDeviceStatistics(device, scheme);
		}
	}

	public void analysis(ScheduleScheme scheme) {

		try {
			analysisDelayReason(scheme.getSchedulePartTasks());

			calcWaitTime(scheme);
			if (scheme.getPersistence()) {
				// 临时所用，用于生成图表
				//saveDeviceUtilData(scheme);
			}
			// 计算加班
			calcOverTime(scheme);

		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void calcOverTime(ScheduleScheme scheme) {
		List<ScheduleOverTime> overTimeList = new ArrayList<ScheduleOverTime>();
		ScheduleOverTime scheduleOverTime = null;
		SegementUse segementUse;
		SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
		String overTimeStartDate = null;
		int overTimeSegements = 0;
		int totalSegement = scheme.getTotalSegement();
		for (SDevice device : scheme.getDeviceMap().values()) {
			if (device.getVirtual() || (device instanceof UcDevice))
				continue;
			for (int i = 0; i < totalSegement; i++) {

				int segementUseState = device.getSegementUse(i);
				if (segementUseState == Resource.RESOURCE_IDLE)
					continue;

				int segementCalendar = scheduledeviceManager.getSegementCalendar(
						device, i);// 取得本段日历
				if (scheduleOverTime == null) {
					scheduleOverTime = new ScheduleOverTime();
					scheduleOverTime.setScheduleUid(scheme.getScheduleUid());
					overTimeSegements = 0;
					overTimeStartDate = null;
				}
				Date ctime = scheme.calDateFromSegement(i);
				String strDate = formatDate.format(ctime);

				if (scheduleOverTime.getOverTimeStart() == null) {
					if (segementCalendar == SCalendar.CALENDAR_CLOSINGTIME) {
						scheduleOverTime.setDevice(device);
						scheduleOverTime.setDeviceUid(device.getResUid());
						scheduleOverTime.setOverTimeStart(ctime);
						overTimeStartDate = strDate;
						overTimeSegements = 1;
						SOperationTask operationTask = device
								.getSegementTask(i);

						scheduleOverTime.setOperationTask(operationTask);

						if (operationTask.getDrawingId() != null) {
							scheduleOverTime.setDrawingId(operationTask
									.getDrawingId());
						} else {
							SPartTask partTask = operationTask.getParentTask();
							scheduleOverTime.setDrawingId(partTask
									.getDrawingId());
						}

						scheduleOverTime.setTaskUid(device.getSegementTask(i)
								.getTaskUid());

					}
				} else {
					overTimeSegements++;
					if (!overTimeStartDate.equals(strDate)
							|| segementCalendar != SCalendar.CALENDAR_CLOSINGTIME) {
						double overTimeWork = overTimeSegements
								* scheme.getScheduleInterval();
						if (overTimeWork > 130)// 短期加班不显示，临时解决中午午休问题
						{
							scheduleOverTime.setOverTimeFinish(ctime);
							scheduleOverTime.setOverTimeWork(overTimeWork);
							overTimeList.add(scheduleOverTime);
						}
						scheduleOverTime = null;

					}
				}

			}

		}

		scheme.setOverTimeList(overTimeList);
		try {
			// 先清空原有的调度方案下各设备的加班信息
//			String scheduleUid = scheme.getScheduleUid();
//			List<ScheduleOverTime> scheduleOverTimeList = scheduleOverTimeDao
//					.getScheduleOverTimeList(scheduleUid);
//			scheduleOverTimeDao.delete(scheduleOverTimeList);
//			if (overTimeList != null && overTimeList.size() > 0) {
//				scheduleOverTimeDao.add(overTimeList);
//			}
		} catch (Exception e) {
			// TODO: handle exception
			log.error(e);
			throw new BaseBusinessException("设备加班保存出错！");
		}
	}

	/**
	 * 以后会用spring配置解决，暂时现用if/else
	 * 
	 * @param scheme
	 * @return
	 */
	public static double calcTargetValue(ScheduleScheme scheme) {
		double targetValue = 0;

		if (scheme.getScheduleTargetType() == null
				|| scheme.getScheduleTargetType().equals(
						ScheduleScheme.SCHEDULE_TARGET_TWT))
			targetValue = calcTwtValue(scheme);
		else if (scheme.getScheduleTargetType().equals(
				ScheduleScheme.SCHEDULE_TARGET_MAKESPAN))
			targetValue = calcMakeSpan(scheme);
		else if (scheme.getScheduleTargetType().equals(
				ScheduleScheme.SCHEDULE_TARGET_TT))
			targetValue = calcTtValue(scheme);
		else
			targetValue = calcTwtValue(scheme);
		return targetValue;
	}

	public static double calcTtValue(ScheduleScheme scheme) {
		double twtValue = 0;
		for (SPartTask partTask : scheme.getSchedulePartTasks()) {
			if (partTask.getLateFinish() != null
					&& partTask.getPlanFinish() != null
					&& partTask.getPlanFinish().after(partTask.getLateFinish())) {
				twtValue += (partTask.getPlanFinish().getTime() - partTask
						.getLateFinish().getTime())
						/ ScheduleUtils.MillSecondsOfDay;
			}
		}
		return twtValue;

	}

	public static double calcTwtValue(ScheduleScheme scheme) {
		double twtValue = 0;
		long tmpMinutes = scheme.getScheduleInterval()
				* ScheduleUtils.MillSecondsOfMinute;
		for (SPartTask partTask : scheme.getSchedulePartTasks()) {
			if (partTask.getLateFinish() != null
					&& partTask.getPlanFinish() != null
					&& partTask.getPlanFinish().after(partTask.getLateFinish())) {
				twtValue += partTask.getDelayCost()
						/ 100
						* (partTask.getPlanFinish().getTime() - partTask
								.getLateFinish().getTime()) / (tmpMinutes);
			}
		}
		return twtValue;

	}

	public static long calcMakeSpan(ScheduleScheme scheme) {
		long makeSpan = 0;
		for (SOperationTask operationTask : scheme.getScheduleOperationTasks()) {
			if (operationTask.getPlanFinishSegment() > makeSpan)
				makeSpan = operationTask.getPlanFinishSegment();
		}
		return makeSpan;

	}

	private void saveDeviceUtilData(ScheduleScheme scheme) {
		DBHandler dbHandler = new DBHandler();
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = dbHandler.getConn();
			// conn.setAutoCommit(false);
			String sqlDelete = " delete from t_schedule_utilize sd where sd.scheduleuid=?";
			dbHandler.createPreparedStatement(sqlDelete);
			dbHandler.stmt.setString(1, scheme.getScheduleUid());
			dbHandler.executeUpdate();
			// modified by hba 增加了需要保存数据的字段，包括准备时间和加工时间
			String sqlInsert = "insert into t_schedule_utilize tsu "
					+ " (SCHEDULEUID,RESUID,TOTALWAITTIME,RES_UTILIZE,RES_LOAD,SEGEMENT_NUM,TOTALSETUPTIME,TOTALRUNTIME) values"
					+ " (?,?,?,?,?,?,?,?)";
			ps = dbHandler.getPreparedStatement(sqlInsert);
			for (SDevice device : scheme.getDeviceMap().values()) {
				if (device.getVirtual())
					continue;

				if (device.getResCapacity() > 1)
					device.setTotalWaitTime(device.getTotalWaitTime()
							/ device.getResCapacity());

				ps.setString(1, scheme.getScheduleUid());
				ps.setString(2, device.getDeviceUid());
				ps.setDouble(3, device.getTotalWaitTime());
				ps.setDouble(4, device.getAverageUtilRation());
				ps.setDouble(5, device.getAverageLoadRation());
				ps.setString(6, "all");
				// added by hba
				ps.setDouble(7, device.getTotalSetupTime());
				ps.setDouble(8, device.getTotalRunTime());
				ps.addBatch();

			}
			ps.executeBatch();
			ps.close();

			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

			String sqlInsertq = "insert into t_schedule_utilize tsu "
					+ " (SCHEDULEUID,RESUID,RES_LOAD,RES_UTILIZE,SEGEMENT_NUM) values"
					+ " (?,?,?,?,?)";
			ps = dbHandler.getPreparedStatement(sqlInsertq);
			for (SDevice device : scheme.getDeviceMap().values()) {
				if (device.getVirtual())
					continue;

				for (DeviceStatistics stat : device.getDeviceStatList()) {
					String dateString = format.format(stat.getDate());
					ps.setString(1, scheme.getScheduleUid());
					ps.setString(2, device.getDeviceUid());
					ps.setDouble(3, stat.getLoadRation());
					ps.setDouble(4, stat.getUtilRation());
					ps.setString(5, dateString);
					ps.addBatch();

				}
			}
			ps.executeBatch();
			ps.close();
			dbHandler.closeStmt();
			// conn.commit();

		} catch (Exception e) {
			// TODO Auto-generated catch block

			log.error(e);

		} finally {
			try {
				if (ps != null)
					ps.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			dbHandler.closeStmt();
			dbHandler.close();
		}
	}

	public void analysisDelayReason(Collection<SPartTask> partTaskList) {
		for (SPartTask partTask : partTaskList) {
			// setStartEndTimeOfPartTask(partTask);
			calcDelayDays(partTask);
			calcTaskWaitTime(partTask);
			// if (partTask.getDelayDays()!=null&&partTask.getDelayDays() > 0) {
			// if (partTask.getSlackFactor() < 1) {
			// partTask.setDelayReason(1);
			// }
			// } else {
			// for (SOperationTask opTask : partTask.getOperationTaskList()) {
			// if (opTask.getWaitTime() > 2) {
			// partTask.setDelayReason(2);
			// break;
			// }
			// }
			// }
			// calcRemainSlack(partTask);
		}
	}

	/**
	 * set the remain slack of the parttask, if it has a time stone task,then
	 * the watch task is the time stone task, else the watch task is the task
	 * finished before the schedule watch day
	 * 
	 * @param partTask
	 */
	public void calcRemainSlack(SPartTask partTask) {
		int scheduleDays = partTask.getScheme().getScheduleDays();
		Date now = partTask.getScheme().getScheduleStart();
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		cal.add(Calendar.DAY_OF_YEAR, scheduleDays);
		Date watchDay = cal.getTime();
		SOperationTask watchTask = null;
		for (SOperationTask operTask : partTask.getOperationTaskList()) {
			if (operTask.getPlanFinish() != null) {
				if (operTask.getPlanFinish().before(watchDay)) {
					watchTask = operTask;
				}
				if (operTask.getPlanFinish().after(watchDay)) {
					break;
				}
			}
		}
		if (watchTask != null) {
			calcRemainSlack(partTask, watchTask);
			partTask.setWatchTask(watchTask);
		} else {
			partTask.setRemainSlack(partTask.getSlackFactor());
		}
	}

	/**
	 * calculate the remain slack from the watch task
	 * 
	 * @param partTask
	 * @param watchTask
	 */
	private void calcRemainSlack(SPartTask partTask, SOperationTask watchTask) {
		try {
			float operaionId = watchTask.getOperationId();
			double remainTaskWork = 0;
			if (partTask.getLateFinish() == null)
				return;
			for (SOperationTask operTask : partTask.getOperationTaskList()) {
				if (operTask.getOperationId() > operaionId) {
					remainTaskWork += operTask.getEstiTaskWork();
				}
			}
			if (remainTaskWork != 0) {
				double remainTime = (partTask.getLateFinish().getTime() - watchTask
						.getPlanFinish().getTime()) / 60000;
				partTask.setRemainSlack(remainTime / remainTaskWork);
			}
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * calculate the wait time of a task
	 * 
	 * @param partTask
	 * 
	 */
	private void calcTaskWaitTime(SPartTask partTask) {
		try {
			double partTaskWaitTime = 0.0;
			for (SOperationTask operationTask : partTask.getOperationTaskList()) {
				Date controlStart = operationTask.getControlEarlyStart();
				Date planStart = operationTask.getPlanStart();
				if (controlStart != null && planStart != null) {
					double waitTime = (double) ((planStart.getTime() - controlStart
							.getTime()) / 60000) / 60 / 24;

					operationTask.setWaitTime(waitTime > 0 ? waitTime : 0);
					partTaskWaitTime = partTaskWaitTime + waitTime;
				}
				/*
				 * double waitTime = (double) ((planStart.getTime() -
				 * controlStart .getTime()) / 60000) / 60 / 24;
				 * operationTask.setWaitTime(waitTime);
				 */
			}
			partTask.setWaitTime(partTaskWaitTime);// add by zhangjiae
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * calculate the delay days of a part task
	 * 
	 * @param partTask
	 */
	private void calcDelayDays(SPartTask partTask) {
		try {
			if (partTask.getLateFinish() != null
					&& partTask.getPlanFinish() != null) {
				int delayDays = (int) Math.round((partTask.getPlanFinish()
						.getTime() - partTask.getLateFinish().getTime())
						/ (60000 * 1440));

				partTask.setDelayDays(delayDays);
			}
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void calcWaitTime(SOperationTask operationTask) {
		try {
			if (log.isDebugEnabled()) {
				if (operationTask.getTaskUid().equals(
						"02c3a89a-68be-4c0d-8b53-9722fdf37b89"))
					log.debug(operationTask);

			}
			if (operationTask.getCalLocked().equals(1)) {
				operationTask.setWaitTime(0);
				return;
			}
			double waitTime = 0;
			ScheduleScheme scheme = operationTask.getScheme();
			Date controlEarlyFinish = scheduleOperationTaskManager
					.getRealControlEarlyFinish(operationTask);
			if (controlEarlyFinish != null
					&& operationTask.getPlanFinish() != null
					&& operationTask.getPlanFinish().after(controlEarlyFinish)) {
				waitTime = (double) ((operationTask.getPlanFinish().getTime() - controlEarlyFinish
						.getTime()) / 60000);

			}

			if (controlEarlyFinish == null
					|| waitTime > scheme.getScheduleInterval()) {
				waitTime = 0;
				Date controlEarlyStart = scheduleOperationTaskManager
						.getRealControlEarlyStart(operationTask);
				if (controlEarlyStart != null
						&& operationTask.getPlanStart() != null
						&& operationTask.getPlanStart()
								.after(controlEarlyStart)) {
					operationTask.setControlEarlyStart(controlEarlyStart);
					waitTime = (double) ((operationTask.getPlanStart()
							.getTime() - controlEarlyStart.getTime()) / 60000);

				}
			} else {
				waitTime = 0;
			}

			// 显示天数
			waitTime = waitTime / (1440);
			operationTask.setWaitTime(waitTime);
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void calcWaitTime(ScheduleScheme scheme) {
		try {
			Date Now = scheme.getScheduleStart();
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(Now);
			int scheduleDays = scheme.getScheduleDays() == null ? 30 : scheme
					.getScheduleDays();

			calendar.add(Calendar.DAY_OF_YEAR, scheduleDays);
			Date deadLine = calendar.getTime();
			for (SOperationTask operTask : scheme.getScheduleOperationTasks()) {
				// 目前是取了所有的调度工序任务，是否需要按照调度状态取呢？ by hba
				if (operTask.getAssignState() != null
						&& operTask.getAssignState() != SOperationTask.ASSNSTATE_SUCCESS) {
					continue;
				}
				if (log.isDebugEnabled()) {
					// if(operTask.getDevice().getDeviceName().indexOf("qg")>0)
					// {
					// log.debug("aaaaaaaaaa");
					// }
				}

				this.calcWaitTime(operTask);

				if (operTask.getDevice() != null) {
					operTask.getDevice().setTotalWaitTime(
							operTask.getDevice().getTotalWaitTime()
									+ operTask.getWaitTime());
					// added by hba 用于统计设备的总准备时间和加工时间
					// if(operTask.getDevice().getDeviceUid().equals("a2"))
					// {
					// log.info("a");
					//						
					// }
					double operTaskSetupTime;
					double runTime = operTask.getEstiRunTime()
							* (operTask.getPlanQty() - operTask
									.getCompleteQty());
					if (operTask.getTaskState() != null
							&& operTask.getTaskState() == SOperationTask.TASKSTATE_PREPARE_COMPLETED
							|| operTask.getCompleteQty() > 0) {
						operTaskSetupTime = 0;
					} else {
						operTaskSetupTime = operTask.getEstiPreTime();
					}
					operTask.getDevice().setTotalSetupTime(
							operTask.getDevice().getTotalSetupTime()
									+ operTaskSetupTime);
					operTask.getDevice().setTotalRunTime(
							operTask.getDevice().getTotalRunTime() + runTime);
					// hba
				}

			}
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}
